#include "simple/geom/iterator.hpp"
#include "simple/geom/algorithm.hpp"

#include <cassert>
#include <memory>

using namespace simple::geom;

template <unsigned width, unsigned height, unsigned step>
void BasicReadWrite()
{
	constexpr vector size{width,height};
	constexpr unsigned pitch = size.x() + step;
	auto image_ptr = std::make_unique<std::array<unsigned, pitch * size.y()>>();
	auto& image = *image_ptr;

	loop(size, [&, pitch, position = unsigned()] (auto i) mutable
	{
		image[i.y() * pitch + i.x()] = position;
		++position;
	});

	{
		iterator begin{image.begin(), 0u};
		iterator end{image.end()-step, size.x()};

		unsigned i = 0;
		while(true)
		{
			auto done = begin == end;
			if(done) break;
			if(done.first_false != 0)
				begin.next(step,done);

			assert(*begin == i);
			++begin;
			++i;
		}
		assert(i == size.x() * size.y());
	}

	{
		vectirator begin{image.begin(), {0u, 0u}};
		vectirator end{image.begin(), {size.x(), size.y()*pitch - step}};

		unsigned i = 0;
		while(true)
		{
			auto done = begin == end;
			if(done) break;
			if(to_disjunction(done))
				begin.next({1u,step}, done);

			assert(*begin == i);
			++begin;
			++i;
		}
		assert(i == size.x() * size.y());
	}

	{
		vectirator begin{image.begin(), {0u, 0u}};
		vectirator end{image.begin(), {size.x(), size.y()*pitch - step}};

		unsigned i = 0;
		while(true)
		{
			auto done = begin == end;
			if(done) break;
			if(to_disjunction(done))
				begin.next({1u,step}, done);

			while(begin != end)
			{
				assert(*begin == i);
				++begin;
				++i;
			}
		}
		assert(i == size.x() * size.y());
	}

	{
		iterator begin{image.begin(), 0u};
		iterator end{image.end()-step, size.x()};

		unsigned i = 0;
		while(true)
		{
			auto done = begin == end;
			if(done) break;
			if(done.first_false != 0)
				begin.next(step,done);

			while(begin != end)
			{
				assert(*begin == i);
				++begin;
				++i;
			};
		}

		assert(i == size.x() * size.y());
	}

}

int main()
{
	BasicReadWrite<1,2,3>();
	BasicReadWrite<1,1,1>();
	BasicReadWrite<1,2,0>();
	BasicReadWrite<1,1,0>();
	// TODO: figure out what's wrong with these and if needs fixing
	// BasicReadWrite<1,0,3>();
	// BasicReadWrite<1,0,0>();
	BasicReadWrite<0,0,0>();
	BasicReadWrite<1000,1000,200>();
	BasicReadWrite<2000,2000,4000>();
	BasicReadWrite<1000,1000,0>();
	BasicReadWrite<2000,2000,0>();
	return 0;
}
